use crate::{fasttime::{a6_timestamp, b3_datetime::DateTimeFT}, IResult};

use super::{bytes_ex, bytes_io::BytesIO};


/// 跨平台的消息
pub struct MessageCross {
    /// 为减小复杂度, id使用request_birth的标准时间戳
    pub id: u64,
    /// 关联id, 用于关联请求与响应
    pub id_relate: u64,
    /// 业务大类
    pub category_big: String,
    /// 业务小类
    pub category_small: String,
    /// 业务细类
    pub category_detail: String,

    // ======== 请求方信息
    /// 消息的请求方(appid)
    pub request_appid: u32,
    /// 消息的请求时间
    pub request_time: DateTimeFT,
    /// 消息的请求数据, 响应时是否返回该数据, 由响应方决定
    pub request_blob: Vec<u8>,

    // ======== 响应方信息
    /// 消息的响应方(appid), =0表示未响应
    pub response_appid: u32,
    /// 接收时间, =0表示未响应
    pub receive_time: DateTimeFT,
    /// 消息的响应时间, =0表示未响应
    pub response_time: DateTimeFT,
    /// 消息的响应数据
    pub response_blob: Vec<u8>,
}

impl MessageCross {
    pub fn new_request(category_big: String, category_small: String, category_detail: String, request_appid: u32, request_blob: Vec<u8>,) -> Self {
        let request_time = DateTimeFT::now();
        let id = request_time.ymd_hmsi_friendly() as u64;
        Self {
            id,
            id_relate: 0,
            category_big,
            category_small,
            category_detail,
            request_appid,
            request_time,
            request_blob,
            response_appid: 0,
            receive_time: DateTimeFT::unix_epoch(),
            response_time: DateTimeFT::unix_epoch(),
            response_blob: vec![],
        }
    }
}

impl MessageCross {
    pub fn category(&self) -> String {
        format!("{}|{}|{}", self.category_big, self.category_small, self.category_detail)
    }
    pub fn to_print(&self) -> String {
        let mut buf = "跨平台的消息:\n".to_string();
        buf.push_str(&format!("\tid: {}\n", self.id));
        buf.push_str(&format!("\tid_relate: {}\n", self.id_relate));
        buf.push_str(&format!("\tcategory: {}\n", self.category()));
        buf.push_str(&format!("\trequest_appid: {}\n", self.request_appid));
        buf.push_str(&format!("\trequest_time: {}\n", self.request_time.to_print()));
        buf.push_str(&format!("\trequest_blob: {}\n", bytes_ex::to_print(&self.request_blob)));
        buf.push_str(&format!("\tresponse_appid: {}\n", self.response_appid));
        buf.push_str(&format!("\treceive_time: {}\n", self.receive_time.to_print()));
        buf.push_str(&format!("\tresponse_time: {}\n", self.response_time.to_print()));
        buf.push_str(&format!("\tresponse_blob: {}\n", bytes_ex::to_print(&self.response_blob)));

        buf
    }
}

impl MessageCross {
    pub fn from_bytes(blob: Vec<u8>) -> IResult<Self> {
        let mut bytes = BytesIO::from_bytes("".to_string(), blob);
        let id = bytes.read_u64_le()?;
        let id_relate = bytes.read_u64_le()?;
        let (_, category_big) = bytes.read_utf8_with_size()?;
        let (_, category_small) = bytes.read_utf8_with_size()?;
        let (_, category_detail) = bytes.read_utf8_with_size()?;

        let request_appid = bytes.read_u32_le()?;
        let request_time = a6_timestamp::from_micros(bytes.read_i64_le()?, None);

        let response_appid = bytes.read_u32_le()?;
        let receive_time = a6_timestamp::from_micros(bytes.read_i64_le()?, None);
        let response_time = a6_timestamp::from_micros(bytes.read_i64_le()?, None);

        let (_, request_blob) = bytes.read_blob_with_size()?;
        let (_, response_blob) = bytes.read_blob_with_size()?;

        let message = Self {
            id,
            id_relate,
            category_big,
            category_small,
            category_detail,
            request_appid,
            request_time,
            request_blob,
            response_appid,
            receive_time,
            response_time,
            response_blob,
        };
        Ok(message)
    }

    pub fn to_bytes(self) -> Vec<u8> {
        let mut bytes = BytesIO::new("".to_string());
        bytes.write_u64_le(self.id);
        bytes.write_u64_le(self.id_relate);
        bytes.write_utf8_with_size(&self.category_big);
        bytes.write_utf8_with_size(&self.category_small);
        bytes.write_utf8_with_size(&self.category_detail);

        bytes.write_u32_le(self.request_appid);
        bytes.write_i64_le(self.request_time.micros_since_unix_epoch);
        
        bytes.write_u32_le(self.response_appid);
        bytes.write_i64_le(self.receive_time.micros_since_unix_epoch);
        bytes.write_i64_le(self.response_time.micros_since_unix_epoch);

        bytes.write_blob_with_size(&self.request_blob);
        bytes.write_blob_with_size(&self.response_blob);

        bytes.to_bytes()
    }
}

#[test]
fn test_message_cross() {
    let year = 2025;
    let message = MessageCross {
        id: 101,
        id_relate: 102,
        category_big: "103".to_string(),
        category_small: "104".to_string(),
        category_detail: "105".to_string(),
        request_appid: 105,
        request_time: DateTimeFT::from_ymd_hms_io_unsafe(year, 6, 7, 8, 9, 10, 11, 12),
        request_blob: vec![106, 107, 108],
        response_appid: 109,
        receive_time: DateTimeFT::from_ymd_hms_io_unsafe(year, 7, 8, 6, 13, 14, 15, 16),
        response_time: DateTimeFT::from_ymd_hms_io_unsafe(year, 8, 6, 7, 17, 18, 19, 20),
        response_blob: vec![109, 110, 111, 112, 113],
    };
    println!("========== 1.\n{}", message.to_print());
    let bytes = message.to_bytes();
    let message2 = MessageCross::from_bytes(bytes).unwrap(); 
    println!("========== 2.\n{}", message2.to_print());
}